package controllers;

import controllers.common.ControllerBase;
import dao.common.BrandManager;
import dao.common.CategoryManager;
import dao.common.ProductManager;
import dao.hibernate.BrandManagerHB;
import dao.hibernate.CategoryManagerHB;
import dao.hibernate.ProductManagerHB;
import models.entities.*;
import models.exceptions.CreateEntityException;
import models.exceptions.GetEntityException;
import models.exceptions.GetEntityListException;
import models.helpers.ImageHelper;
import models.helpers.UserHelper;
import models.repository.ProductRepositorySQL;
import models.repository.common.ProductRepository;
import models.shop.Brand;
import models.shop.Category;
import models.shop.Mail.Message;
import models.shop.User;
import models.shop.path.ProductFilter;
import net.tanesha.recaptcha.ReCaptchaResponse;
import notifiers.Mails;
import play.Play;
import play.cache.Cache;
import play.data.validation.Valid;
import play.data.validation.Validation;

import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.List;

public class Product extends ControllerBase {

    @Deprecated
    private static ProductRepository repository = new ProductRepositorySQL();
    private static ProductManager productManager = new ProductManagerHB();
    private static BrandManager brandManager = new BrandManagerHB();
    private static CategoryManager categoryManager = new CategoryManagerHB();

    public static void display(int id) throws GetEntityListException, CreateEntityException, GetEntityException, IOException {
        models.shop.Product product = productManager.getById(id, true);
        if (product == null)
            notFound("Товар не найден");
        ProductFilter filter = new ProductFilter(product.category.id, 1, 0, 1, id);
        SiteMapPath siteUrls = productManager.getSitePath(filter);
        if (product == null) {
            error(404, "product not found");
            return;
        }
        models.shop.User user = UserHelper.getUser(session);
        boolean isAdmin = user.getIsAdmin();
        render(product, siteUrls, filter, isAdmin);
    }

    public static void productList(Integer categoryId, Integer pageNumber, Integer brandId, Integer brandPage, Integer productId) throws IOException, GetEntityListException, CreateEntityException, GetEntityException {

        ProductFilter filter = new ProductFilter(categoryId, pageNumber, brandId, brandPage, productId);
        User user = UserHelper.getUser(session);
        boolean isAdmin = user.getIsAdmin();
        setCache(3600);
        if (request.isAjax()) {
            List<Brand> brands = getBrands(filter);
            render("/Product/brandbar.html", brands, filter);
        }
        SiteMapPath siteUrls = productManager.getSitePath(filter);
        if (filter.productId > 0) {

            productManager.clearCache();
            models.shop.Product product = productManager.getById(productId);
            render("/Product/display.html", product, siteUrls, filter, isAdmin);
        } else {

            PaginatedList<models.shop.Product> productList = productManager.list(filter);
            models.shop.Category category = siteUrls.currentCategory;
            List<Category> categories = getCategories(filter.brandId, category.id);
            List<Brand> brands = null;
            Brand selectedBrand = null;
            int brandsPagesCount = 0;
            if (filter.brandId == 0) {
                PaginatedList<Brand> brandList = getPagedBrands(filter);
                brands = brandList.items;
                brandsPagesCount = (int) brandList.getPageCount();
            } else
                selectedBrand = brandManager.getById(filter.brandId);
            render("/Product/list.html", productList, brandsPagesCount,
                    siteUrls, filter, isAdmin,
                    category, brands,
                    selectedBrand, categories);
        }
    }

    private static PaginatedList<Brand> getPagedBrands(ProductFilter filter) {
        String brandKey = String.format("pagedBrandList_%1$s_%2$s", filter.categoryId, filter.brandPage);
        PaginatedList<Brand> brands = (PaginatedList<Brand>) Cache.get(brandKey);
        if (brands == null) {
            brands = brandManager.paginatedList(filter);
            Cache.add(brandKey, brands, "30mn");
        }
        return brands;
    }

    private static List<Brand> getBrands(ProductFilter filter) {
        setCache(3600);
        String brandKey = String.format("brandList_%1$s_%2$s", filter.categoryId, filter.brandPage);
        List<Brand> brands = (List<Brand>) Cache.get(brandKey);
        if (brands == null) {
            brands = brandManager.list(filter);
            Cache.add(brandKey, brands, "30mn");
        }
        return brands;
    }

    private static List<models.shop.Category> getCategories(Integer brandId, int categoryId) {
        String categoryKey = String.format("categoryList_%1$s_%2$s", categoryId, brandId);
        List<models.shop.Category> categories = (List<models.shop.Category>) Cache.get(categoryKey);
        if (categories == null) {
            categories = categoryManager.listByParentId(categoryId, brandId);
            Cache.add(categoryKey, categories, "30mn");
        }
        return categories;
    }

    public static void question(Integer categoryId, Integer pageNumber, Integer brandId, Integer brandPage, Integer productId) throws IOException, GetEntityListException {
        if (productId != null) {
            models.shop.Product product = productManager.getById(productId);

            ProductFilter filter = new ProductFilter(categoryId, pageNumber, brandId, brandPage, productId);
            filter.showProduct = true;
            SiteMapPath siteUrls = productManager.getSitePath(filter);
            render(product, siteUrls, filter);
        }
    }

    public static void categoryList() throws IOException, GetEntityListException, CreateEntityException, GetEntityException {
        productList(1, 1, 0, 1, 0);
    }

    @Deprecated
    public static void search(String q, int pageNumber, int pageSize, int categoryId, int brandId) throws GetEntityListException, IOException {
        PaginatedList<models.shop.Product> productList = productManager.search(q, pageNumber, pageSize, categoryId, brandId);
        render(productList, q);
    }

    public static void askQuestion(@Valid Message message,
                                   Integer categoryId,
                                   Integer pageNumber,
                                   Integer brandId,
                                   Integer brandPage,
                                   Integer productId) throws GetEntityListException, CreateEntityException, GetEntityException, IOException {
        ReCaptchaResponse captchaResponse = ValidateCaptcha();
        if (Validation.hasErrors() || !captchaResponse.isValid()) {
            ProductFilter filter = new ProductFilter(categoryId, pageNumber, brandId, brandPage, productId);
            params.flash();
            Validation.keep();
            if (!captchaResponse.isValid()) {
                flash.error("Код проверки неверный");
            } else {
                flash.error("Shop.contacts.requiredall");
            }
            question(categoryId, pageNumber, brandId, brandPage, productId);
        } else {
            Mails.askQuestion(message, productId);
            flash.success("Shop.contacts.sendsuccessful");
            question(categoryId, pageNumber, brandId, brandPage, productId);
        }
    }

    @Deprecated
    public static void list(Integer categoryId, Integer brandId, Integer pageNumber, Integer pageSize, String q) throws GetEntityListException, GetEntityException, IOException, CreateEntityException {
        productList(categoryId, pageNumber, brandId, 1, 0);
        return;

    }

    @Deprecated
    public static void brandImage(int id, int number, int width, int height, String type) throws GetEntityException, IOException {
        ImageHelper.checkImageSize(width, height);
        if (number == 0)
            number = 1;
        //TODO: something wrong with type binding. hardcode it
        type = "png";
        InputStream brandImage = repository.getBrandImage(id, number, width, height, Play.getFile("data").toString(), type);
        setCache(1000000);
        renderBinary(brandImage, String.format("%1$s_%2$sx%3$s.jpg", id, width, height), "image/jpg", true);
    }

    @Deprecated
    public static void productImage(int id, int number, int width, int height, String type) throws IOException, GetEntityException {
        if (number == 0)
            number = 1;
        ImageHelper.checkImageSize(width, height);
        //TODO: something wrong with type binding. hardcode it
        type = "png";
        InputStream productImage = repository.getProductImage(id, number, width, height, Play.getFile("data").toString(), type);

        setCache(1000000);
        renderBinary(productImage, MessageFormat.format("{0}_{1}x{2}.{3}", id, width, height, type), "image/jpg", true);
    }

    @Deprecated
    public static void defaultImage(int width, int height, String type) throws IOException, GetEntityException {
        //TODO: something wrong with type binding. hardcode it
        ImageHelper.checkImageSize(width, height);
        type = "png";
        InputStream defaultImage = ImageHelper.getDefaultProductImage(Play.getFile("data").toString(), width, height, type);
        setCache(1000000);
        renderBinary(defaultImage);
    }

    @Deprecated
    public static void createCategory(CategoryEntity category) throws CreateEntityException, IOException {
        repository.createCategory(category);
        render();
    }

    @Deprecated
    public static void gallery(int productId, int imageNumber) throws GetEntityException, IOException {
        int imagesCount = repository.getImagesCount(productId);
        render(productId, imageNumber, imagesCount);
    }
}
